package org.lsda.sched;

import static org.quartz.CronScheduleBuilder.cronSchedule;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
import static org.quartz.TriggerBuilder.newTrigger;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

import org.lsda.job.LsdaAction;
import org.lsda.job.LsdaJob;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.GroupMatcher;

public class LsdaScheduler {

	// construct the factory
	public static SchedulerFactory schedFact = new StdSchedulerFactory();

	// start up the scheduler
	public static void startup() throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		sched.start();
		System.out.println("StartUp......");
	}
	
	// shut down
	public static void shutdown() throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		sched.shutdown();
		System.out.println("ShutDown......");
	}
	
	public static boolean isUp() throws SchedulerException{
		Scheduler sched = schedFact.getScheduler();
		return sched.isStarted();
		
	}
	
	public static boolean isDown() throws SchedulerException{
		Scheduler sched = schedFact.getScheduler();
		return sched.isShutdown();
	}
	
	public static boolean isStandby() throws SchedulerException{
		Scheduler sched = schedFact.getScheduler();
		return sched.isInStandbyMode();
	}
	
	// list all the JobDetails
	public static ArrayList<JobDetail> listJobs() throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		ArrayList<JobDetail> jds = new ArrayList<JobDetail>();
		List<String> groups = sched.getJobGroupNames();
		for (String groupName : groups) {
			Set<JobKey> jks = sched.getJobKeys(GroupMatcher
					.jobGroupEquals(groupName));
			for (JobKey jk : jks) {
				jds.add(sched.getJobDetail(jk));
			}
		}
		return jds;
	}

	// list actions
	public static ArrayList<LsdaAction> listActions(String jobGroup,
			String jobName) throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		JobKey jk = new JobKey(jobName, jobGroup);
		JobDetail jd = sched.getJobDetail(jk);
		return (ArrayList<LsdaAction>) jd.getJobDataMap().get("actions");
	}

	// get trigger
	public static Trigger getTrigger(String triggerGroup, String triggerName)
			throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		TriggerKey tk = new TriggerKey(triggerName, triggerGroup);
		Trigger trigger = sched.getTrigger(tk);
		return trigger;
	}

	// get all the triggers associated with a job
	public static List<? extends Trigger> getTriggers(String jobGroup,
			String jobName) throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		JobKey jk = new JobKey(jobName, jobGroup);
		return sched.getTriggersOfJob(jk);
	}

	// delete job from scheduler
	public static void deleteJob(String jobName, String jobGroup)
			throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		JobKey jk = new JobKey(jobName, jobGroup);
		sched.deleteJob(jk);
	}

	// addJob
	public static void addJob(String jobName, String jobGroup,
			String description) throws SchedulerException {
		ArrayList<LsdaAction> actions = new ArrayList<LsdaAction>();
		Scheduler sched = schedFact.getScheduler();
		JobDataMap jdm = new JobDataMap();
		jdm.put("groupId", jobGroup);
		jdm.put("jobId", jobName);
		jdm.put("sched_seq", -1);
		jdm.put("actions", actions);
		jdm.put("description", description);
		jdm.put("updateTime", now());
		//
		// // build the JobDetail instance
		JobDetail jobDetail = newJob(LsdaJob.class).storeDurably(true)
				.withIdentity(jobName, jobGroup).usingJobData(jdm).build();
		sched.addJob(jobDetail, false);
	}

	public static void updateJob(String jobName, String jobGroup,
			String description) throws SchedulerException {
		ArrayList<LsdaAction> actions = new ArrayList<LsdaAction>();
		Scheduler sched = schedFact.getScheduler();
		JobDetail jd = sched.getJobDetail(new JobKey(jobName, jobGroup));

		JobDataMap jdm = jd.getJobDataMap();
		jdm.put("description", description);
		jdm.put("updateTime", now());

		//
		// // build the JobDetail instance
		JobDetail jobDetail = newJob(LsdaJob.class).storeDurably(true)
				.withIdentity(jobName, jobGroup).usingJobData(jdm).build();
		sched.addJob(jobDetail, true);
	}

	// add a job
	public static void addJob(JobDetail jobDetail, Trigger trigger)
			throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		sched.scheduleJob(jobDetail, trigger);
	}

	// add a job
	public static void addJob(JobDetail jobDetail) throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		sched.addJob(jobDetail, true);
		sched.triggerJob(jobDetail.getKey());
	}

	// get the job
	public static JobDetail getJobDetail(String jobGroup, String jobName)
			throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		JobKey key = new JobKey(jobName, jobGroup);
		return sched.getJobDetail(key);

	}

	public static Trigger createTrigger(String jobName, String jobGroup,
			String triggerName, String triggerGroup, int schedType, Date start,
			Date end, int repeat, int interval, String crontab, String desc)
			throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		Trigger trigger = null;
		if (schedType == 0)
			trigger = createSimpleTrigger(jobName, jobGroup, triggerName,
					triggerGroup, start, end, repeat, interval, crontab, desc);
		else if (schedType == 1)
			trigger = createCronTrigger(jobName, jobGroup, triggerName,
					triggerGroup, start, end, repeat, interval, crontab, desc);

		if (trigger != null)
			sched.scheduleJob(trigger);
		return trigger;
	}

	public static SimpleTrigger createSimpleTrigger(String jobName,
			String jobGroup, String triggerName, String triggerGroup,
			Date start, Date end, int repeat, int interval, String crontab,
			String desc) {
		SimpleScheduleBuilder ssb = simpleSchedule();
		ssb = ssb.withIntervalInMilliseconds(interval);
		if (repeat == -1)
			ssb = ssb.repeatForever();
		else
			ssb = ssb.withRepeatCount(repeat);

		TriggerBuilder<Trigger> tb = newTrigger().withIdentity(triggerName,
				triggerGroup).withDescription(desc);
		if (start != null)
			tb = tb.startAt(start);
		if (end != null)
			tb = tb.endAt(end);
		SimpleTrigger trigger = tb.withSchedule(ssb).forJob(jobName, jobGroup)
				.build();
		return trigger;
	}

	public static CronTrigger createCronTrigger(String jobName,
			String jobGroup, String triggerName, String triggerGroup,
			Date start, Date end, int repeat, int interval, String crontab,
			String desc) {
		CronScheduleBuilder csb = cronSchedule(crontab);

		TriggerBuilder<Trigger> tb = newTrigger().withIdentity(triggerName,
				triggerGroup).withDescription(desc);
		if (start != null)
			tb = tb.startAt(start);
		if (end != null)
			tb = tb.endAt(end);
		CronTrigger trigger = tb.withSchedule(csb).forJob(jobName, jobGroup)
				.build();
		return trigger;
	}

	// unschedule the job
	public static void unscheduleTrigger(String triggerName, String triggerGroup)
			throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		sched.unscheduleJob(new TriggerKey(triggerName, triggerGroup));
	}

	public static void updateTrigger(String jobName, String jobGroup,
			String triggerName, String triggerGroup, int schedType, Date start,
			Date end, int repeat, int interval, String crontab, String desc)
			throws SchedulerException {
		unscheduleTrigger(triggerName, triggerGroup);
		LsdaScheduler.createTrigger(jobName, jobGroup, triggerName,
				triggerGroup, schedType, start, end, repeat, interval, crontab,
				desc);
	}

	// create an action
	public static LsdaAction createAction(String jobName, String jobGroup,
			String command, String parameter,String desc) throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		JobKey jk = new JobKey(jobName, jobGroup);
		JobDetail jd = sched.getJobDetail(jk);

		ArrayList<LsdaAction> actions = (ArrayList<LsdaAction>) jd
				.getJobDataMap().get("actions");
		LsdaAction action = new LsdaAction();
		action.setActionSeq(actions.size() + 1);
		action.setPrgName(command);
		action.setPrgParam(parameter);
		action.setInfo(desc);
		actions.add(action);

		jd.getJobDataMap().put("actions", actions);
		// sched
		sched.addJob(jd, true);
		return action;

	}

	//update action
	public static void updateAction(String jobName, String jobGroup,
			String command, String parameter, int actSeq)
			throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		JobKey jk = new JobKey(jobName, jobGroup);
		JobDetail jd = sched.getJobDetail(jk);

		ArrayList<LsdaAction> actions = (ArrayList<LsdaAction>) jd
				.getJobDataMap().get("actions");
		LsdaAction action = new LsdaAction();
		action.setActionSeq(actSeq);
		action.setPrgName(command);
		action.setPrgParam(parameter);
		actions.set(actSeq - 1, action);

		jd.getJobDataMap().put("actions", actions);
		// sched
		sched.addJob(jd, true);

	}
	
	//delete action
	public static void deleteAction(String jobName, String jobGroup, int actSeq)
			throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		JobKey jk = new JobKey(jobName, jobGroup);
		JobDetail jd = sched.getJobDetail(jk);

		ArrayList<LsdaAction> actions = (ArrayList<LsdaAction>) jd
				.getJobDataMap().get("actions");
		actions.remove(actSeq-1);

		jd.getJobDataMap().put("actions", actions);
		// sched
		sched.addJob(jd, true);
	}

	// delete job from scheduler
	public static void deleteJob(JobDetail jd) throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		sched.deleteJob(jd.getKey());
	}

	// schedule job
	public static void scheduleJob(JobDetail jd, Trigger trigger)
			throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		sched.scheduleJob(jd, trigger);
	}

	public static Trigger createSimpleTrigger() {
		return null;

	}

	public static void clearJobs() throws SchedulerException {
		Scheduler sched = schedFact.getScheduler();
		sched.clear();

	}

	public static Trigger createCronTrigger() {
		return null;
	}


	public static String now() {
		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		// get current date time with Date()
		Date date = new Date();
		return dateFormat.format(date);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		try {
			isUp();
			if (true)
				return;
			System.out.println(now());

			listJobs();
			// clearJobs();
			// listJobs();
			// clearJobs();

			listJobs();

			// start up the scheduler
			// startup();
			// // // construct the action
			ArrayList<LsdaAction> actions = new ArrayList<LsdaAction>();
			LsdaAction action = new LsdaAction();
			action.setPrgName("date");
			action.setPrgParam(" -m ");
			action.setActionSeq(1);
			action.setInfo("show date");
			actions.add(action);

			// // // construct the action
			action = new LsdaAction();
			action.setPrgName("echo ");
			action.setPrgParam(" map/reduce relief");
			// actions = new ArrayList<LsdaAction>();
			action.setActionSeq(2);
			action.setInfo("print map/reduce relief");
			actions.add(action);
			//
			// // build job data map
			JobDataMap jdm = new JobDataMap();
			jdm.put("groupId", "PDP");
			jdm.put("jobId", "map/reduce relief");
			jdm.put("sched_seq", -1);
			jdm.put("actions", actions);
			jdm.put("description", "employ map/reduce relief");
			jdm.put("updateTime", now());
			//
			// // build the JobDetail instance
			JobDetail job = newJob(LsdaJob.class)
					.withIdentity("map/reduce relief", "PDP").usingJobData(jdm)
					.build();

			//
			// // // build the rule for schedule the job
			Trigger trigger = newTrigger()
					.withIdentity("map/reduce relief", "PDP")
					.withDescription("job with every 1000 seconds")
					.withSchedule(
					// simpleSchedule().repeatForever()
					// .withIntervalInHours(1)
							cronSchedule("0 0/10 * * * ?"))
					.forJob("map/reduce relief", "PDP").build();
			System.out.println(trigger.getDescription());

			//
			// // unscheduleJob(trigger);
			//
			// // put the job into the scheduler to schedule
			addJob(job, trigger);

			// build job data map
			// JobDataMap jdm = new JobDataMap();
			// jdm.put("groupId", "default");
			// jdm.put("jobId", "job3");
			// jdm.put("sched_seq", -1);
			// jdm.put("actions", actions);
			//
			// // build the JobDetail instance
			// JobDetail job = newJob(LsdaJob.class)
			// .withIdentity("job4", "default").usingJobData(jdm).build();
			//
			// // // build the rule for schedule the job
			// Trigger trigger = newTrigger()
			// .withIdentity("myTrigger4", "default")
			// .withDescription("job with every 10 seconds")
			// .withSchedule(
			// simpleSchedule().repeatForever()
			// .withIntervalInHours(1))
			// .forJob("job4", "default").build();
			//
			// Trigger t = newTrigger().withIdentity("bbb", "aaa").build();
			//
			// unscheduleJob(t);

			// put the job into the scheduler to schedule
			// scheduleJob(job, trigger);

		} catch (SchedulerException se) {
			se.printStackTrace();
		}
	}

}
